From 9ac53dcc3bbb3d428c02a05104d2a848a090ddaf Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Sat, 1 Oct 2011 04:54:44 +0000 Subject: [PATCH] Made provideIPCIDRs() not add a '/' if there is no prefix length. Fixes bug 31234. --- includes/IP.php | 5 +- includes/resourceloader/ResourceLoader.php | 88 ++++++++++++++++++++-- tests/phpunit/includes/IPTest.php | 23 ++++++ 3 files changed, 110 insertions(+), 6 deletions(-) diff --git a/includes/IP.php b/includes/IP.php index 152236f738..2f262e3217 100644 --- a/includes/IP.php +++ b/includes/IP.php @@ -705,8 +705,11 @@ class IP { * @param $range String: IP address to normalize * @return string */ - public static function sanitizeRange( $range ){ + public static function sanitizeRange( $range ) { list( /*...*/, $bits ) = self::parseCIDR( $range ); + if ( $bits === false ) { + return $range; // wasn't actually a range + } list( $start, /*...*/ ) = self::parseRange( $range ); $start = self::formatHex( $start ); return "$start/$bits"; diff --git a/includes/resourceloader/ResourceLoader.php b/includes/resourceloader/ResourceLoader.php index b1c4b727ab..44d71d01e8 100644 --- a/includes/resourceloader/ResourceLoader.php +++ b/includes/resourceloader/ResourceLoader.php @@ -353,7 +353,17 @@ class ResourceLoader { * @param $context ResourceLoaderContext: Context in which a response should be formed */ public function respond( ResourceLoaderContext $context ) { - global $wgCacheEpoch; + global $wgCacheEpoch, $wgUseFileCache; + + // Use file cache if enabled and available... + if ( $wgUseFileCache ) { + $type = 'resources-' . ( $context->getOnly() === 'styles' ? 'css' : 'js' ); + $hash = sha1( $context->getHash() . implode( ',', $context->getModules() ) ); + $fileCache = ObjectFileCache::newFromKey( $hash, $type ); + if ( $this->tryRespondFromFileCache( $fileCache, $context ) ) { + return; // output handled + } + } // Buffer output to catch warnings. Normally we'd use ob_clean() on the // top-level output buffer to clear warnings, but that breaks when ob_gzhandler @@ -432,6 +442,15 @@ class ResourceLoader { ob_end_clean(); echo $response; + // Save response to file cache if enabled + if ( isset( $fileCache ) && !$private && !$exceptions && !$missing ) { + $request = $context->getRequest(); + // Don't cache URLs that the user was not given by site + if ( $request->getVal( 'fckey' ) == self::fileCacheKey( $request->getRequestURL() ) ) { + $fileCache->saveText( $response ); + } + } + wfProfileOut( __METHOD__ ); } @@ -519,6 +538,50 @@ class ResourceLoader { return false; } + /** + * Send out code for a response from file cache if possible + * + * @param $fileCache ObjectFileCache: Cache object for this request URL + * @param $context ResourceLoaderContext: Context in which to generate a response + * @return bool If this found a cache file and handled the response + */ + protected function tryRespondFromFileCache( + ObjectFileCache $fileCache, ResourceLoaderContext $context + ) { + global $wgResourceLoaderMaxage; + // Buffer output to catch warnings. + ob_start(); + // Get the maximum age the cache can be + $maxage = is_null( $context->getVersion() ) + ? $wgResourceLoaderMaxage['unversioned']['server'] + : $wgResourceLoaderMaxage['versioned']['server']; + // Minimum timestamp the cache file must have + $good = $fileCache->isCacheGood( wfTimestamp( TS_MW, time() - $maxage ) ); + if ( !$good ) { + try { // RL always hits the DB on file cache miss... + wfGetDB( DB_SLAVE ); + } catch( DBConnectionError $e ) { // ...check if we need to fallback to cache + $good = $fileCache->isCacheGood(); // cache existence check + } + } + if ( $good ) { + $ts = $fileCache->cacheTimestamp(); + // Send content type and cache headers + $this->sendResponseHeaders( $context, $ts, false ); + // If there's an If-Modified-Since header, respond with a 304 appropriately + if ( $this->tryRespondLastModified( $context, $ts ) ) { + return; // output handled (buffers cleared) + } + $response = $fileCache->fetchText(); + // Remove the output buffer and output the response + ob_end_clean(); + echo $response . "\n/* Cached {$ts} */"; + return true; // cache hit + } + ob_end_clean(); + return false; // cache miss + } + /** * Generates code for a response * @@ -912,14 +975,29 @@ class ResourceLoader { */ public static function makeLoaderURL( $modules, $lang, $skin, $user = null, $version = null, $debug = false, $only = null, $printable = false, $handheld = false, $extraQuery = array() ) { - global $wgLoadScript; + global $wgLoadScript, $wgUseFileCache; $query = self::makeLoaderQuery( $modules, $lang, $skin, $user, $version, $debug, $only, $printable, $handheld, $extraQuery ); - + + $url = wfAppendQuery( $wgLoadScript, $query ); + // Avoid deliberate FS pollution with hand-made URLs + if ( $wgUseFileCache ) { + $url .= '&fckey=' . self::fileCacheKey( $url . '&*' ); + } + // Prevent the IE6 extension check from being triggered (bug 28840) - // by appending a character that's invalid in Windows extensions ('*') - return wfExpandUrl( wfAppendQuery( $wgLoadScript, $query ) . '&*', PROTO_RELATIVE ); + // by appending a character that's invalid in Windows extensions ('*') + return $url . '&*'; + } + + /** + * Get a filecache key for a load.php URL + * @return string + */ + protected static function fileCacheKey( $url ) { + global $wgSecretKey; + return sha1( preg_replace( '/&fckey=[^&]*/', '', $url ) . $wgSecretKey . wfWikiID() ); } /** diff --git a/tests/phpunit/includes/IPTest.php b/tests/phpunit/includes/IPTest.php index acc6ebd4cf..74dd0ab9bd 100644 --- a/tests/phpunit/includes/IPTest.php +++ b/tests/phpunit/includes/IPTest.php @@ -482,4 +482,27 @@ class IPTest extends MediaWikiTestCase { ); } + /** + * Test for IP::sanitizeRange() + * @dataProvider provideIPCIDRs + */ + function testSanitizeRange( $input, $expected, $description ) { + $this->assertEquals( $expected, IP::sanitizeRange( $input ), $description ); + } + + /** + * Provider for IP::testSanitizeRange() + */ + function provideIPCIDRs() { + return array( + array( '35.56.31.252/16', '35.56.0.0/16', 'IPv4 range' ), + array( '135.16.21.252/24', '135.16.21.0/24', 'IPv4 range' ), + array( '5.36.71.252/32', '5.36.71.252/32', 'IPv4 silly range' ), + array( '5.36.71.252', '5.36.71.252', 'IPv4 non-range' ), + array( '0:1:2:3:4:c5:f6:7/96', '0:1:2:3:4:C5:0:0/96', 'IPv6 range' ), + array( '0:1:2:3:4:5:6:7/120', '0:1:2:3:4:5:6:0/120', 'IPv6 range' ), + array( '0:e1:2:3:4:5:e6:7/128', '0:E1:2:3:4:5:E6:7/128', 'IPv6 silly range' ), + array( '0:1:A2:3:4:5:c6:7', '0:1:A2:3:4:5:c6:7', 'IPv6 non range' ), + ); + } } -- 2.20.1